import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.TableEditor;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.events.KeyAdapter;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.MouseAdapter;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Dialog;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.TableItem;
import org.eclipse.swt.widgets.Text;

/**
 * The dialog used to select the pre-tasks of a task.
 * 
 * @author zhongnanhai
 *
 */
public class PretasksDialog extends Dialog{
	/**Current edited task.*/
	private Task task;
	/**All of the tasks.*/
	private List<Task> tasks = new ArrayList<Task>();
	/**The pre-tasks this dialog will return.*/
	private HashMap<Task,Integer> pretasks = new HashMap<Task,Integer>();
	/**
	 * The constructor with a default style.
	 * @param parent its parent window
	 */
	public PretasksDialog(Shell parent){
		this(parent,SWT.DIALOG_TRIM | SWT.CLOSE);
	}
	/**
	 * The constructor of PretasksDialog.
	 * 
	 * @param parent its parent window
	 * @param style its specific style
	 */
	public PretasksDialog(Shell parent, int style) {
		super(parent, style);
		// TODO Auto-generated constructor stub
	}
	/**
	 * Set the current edited task.
	 * 
	 * @param task current Task object
	 */
	public void setTask(Task task){
		this.task = task;
	}
	/**
	 * Set the tasks the this dialog will show, and the pre-conditions between tasks
	 * would be used
	 * 
	 * @param tasks all of the tasks
	 */
	public void setTasks(ArrayList<Task> tasks){
		this.tasks = tasks;
	}
	/**
	 * The open function of a dialog class
	 * @return the pretasks list
	 */
	public HashMap<Task,Integer> open(){
		Shell shell = new Shell(getParent(),getStyle());
		shell.setText("Set Pre-tasks");
		createContents(shell);
		shell.pack();
		int x = getParent().getBounds().x + (getParent().getBounds().width - shell.getBounds().width)/2;
		int y = getParent().getBounds().y + (getParent().getBounds().height - shell.getBounds().height)/2;
		shell.setLocation(x,y);
		shell.open();
		Display display = getParent().getDisplay();
		while(!shell.isDisposed()){
			if(display.readAndDispatch())
				display.sleep();
		}
		return pretasks;
	}
	/**
	 * Check if there exists a circle in the task graph, which means a task will be
	 * completed before another task that depends on its completion. If the situation
	 * occur, then the user may set a wrong pre orders.
	 * @param pretasks current selected pre-tasks
	 * @param return good condition,true;else false;
	 */
	private boolean check(Map<Task,Integer> pretasks){
		if(pretasks.size()>0){
			if(pretasks.containsKey(task)){
				return false;
			}else{
				for(Task pretask:pretasks.keySet()){
					if(!check(pretask.getPreTasks()))
						return false;
				}
			}
		}
		return true;
	}
	/**
	 * Create all of the contents/controls of this dialog.
	 * @param shell the dialog window
	 */
	private void createContents(final Shell shell){
		shell.setLayout(new FillLayout());
		GC gc = new GC(shell.getDisplay());
		final Table taskList = new Table(shell,SWT.BORDER | SWT.CHECK |SWT.FULL_SELECTION);
		taskList.setHeaderVisible(false);
		
		final TableEditor editor = new TableEditor(taskList);
	    editor.horizontalAlignment = SWT.LEFT;
	    editor.grabHorizontal = true;
		
		TableColumn[] columns = new TableColumn[2];
		for(int i=0;i<columns.length;i++){
			columns[i] = new TableColumn(taskList,SWT.CENTER);
		}
		int columnWidth = 0;
		for(int i = 0;i<tasks.size();i++){
			Task t = tasks.get(i);
			TableItem item = new TableItem(taskList,SWT.NONE);
			item.setText(t.getName());
			
			int strWidth = gc.stringExtent(t.getName()).x;//calculate the string width in pixel
			if(strWidth > columnWidth)
				columnWidth = strWidth;
			
			if(task.getPreTasks().containsKey(t)){
				item.setChecked(true);
				item.setText(1, task.getPreTasks().get(t)+"%");
			}else{
				item.setChecked(false);
				item.setText(1, 50+"%");
			} 
		}
		
		columns[0].setWidth(columnWidth+30);
		columns[0].setResizable(false);
		columns[1].setWidth(45);
		columns[1].setResizable(false);
		
		taskList.addMouseListener(new MouseAdapter(){
			public void mouseDown(MouseEvent event){
				Control old = editor.getEditor();
				if(old!=null)
					old.dispose();
				// Determine where the mouse was clicked
		        Point pt = new Point(event.x, event.y);
		        // Determine which row was selected
		        final TableItem item = taskList.getItem(pt);
		        if (item != null){
		        	// Determine which column was selected
		        	int column = -1;
		        	for (int i = 0, n = taskList.getColumnCount(); i < n; i++) {
		        		Rectangle rect = item.getBounds(i);
		        		if (rect.contains(pt)) {
		        			// This is the selected column
		        			column = i;
		        			break;
		        		}
		        	}
		        	if (column == 1){
		        		final int col = column;
		        		final Text text = new Text(taskList,SWT.BORDER);
		        		text.setFocus();
		        		editor.setEditor(text, item, column);
		        		text.addKeyListener(new KeyAdapter(){
		        			public void keyPressed(KeyEvent e){
		        				if(e.keyCode==SWT.CR){
		        					String str = text.getText();
		        					try{
		        						int num = Integer.parseInt(str);
		        						if(num<=100&&num>=0)
		        							item.setText(col, num+"%");
		        						text.dispose();
		        					}catch(Exception ex){
		        						text.dispose();
		        					}
		        				}
		        			}
		        		});
		        	}
		        }
			}
		});
		
		//add actions
		shell.addDisposeListener(new DisposeListener(){
			@Override
			public void widgetDisposed(DisposeEvent e) {
				// TODO Auto-generated method stub
				HashMap<Task,Integer> temp = new HashMap<Task,Integer>();
				for(int i = 0 ;i<taskList.getItemCount();i++){
					if(taskList.getItem(i).getChecked()){
						String str = taskList.getItem(i).getText(1);
						str = str.substring(0, str.length()-1);
						int strength = Integer.parseInt(str);
						
						temp.put(tasks.get(i),strength);
					}
				}
				if(!check(temp)){
					Utilities.showMessage(shell,SWT.ICON_ERROR,"Your selection may cause an interdependence between the tasks,please check again.");
					pretasks = null;//if wrong,return null
					return;
				}else{
					pretasks = temp;
				}
			}
			
		});
	}
}
